package edu.kit.csl.pisa.datatypes;

/*
This file is part of the PISA Alignment Tool.

Copyright (C) 2013
Karlsruhe Institute of Technology
Cognitive Systems Lab (CSL)
Felix Stahlberg

PISA is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

PISA is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with PISA. If not, see <http://www.gnu.org/licenses/>.
*/

import java.util.Iterator;

/**
 * This class encapsulates a triple (a, e, f) where e is the English sentence,
 * f is the French phoneme sequence, and a is an alignment between e and f. The
 * class implements the GoF design pattern Fly-weight together with
 * {@link SentencePair}.
 * 
 * @see Alignment
 * @see SentencePair
 */
public class SentenceAlignment implements Iterable<AlignmentPosition> {

	private Alignment a;
	private final Sentence e, f;
	private double score;
	
	/**
	 * Sole constructor.
	 * 
	 * @param a the alignment
	 * @param e the English (source language) sentence
	 * @param f the French (target language) phoneme sequence
	 * @param score the score of this alignment
	 */
	public SentenceAlignment(Alignment a, final Sentence e, final Sentence f,
			double score) {
		this.a = a;
		this.e = e;
		this.f = f;
		this.score = score;
	}
	
	/**
	 * This method checks if the alignment is internally consistent and matches
	 * the lengths of the target and source language. If one of the member
	 * variables are set to null, it returns false.
	 * 
	 * @return TRUE if this instance refers to a possible consistent alignment
	 */
	public boolean isConsistent() {
		if (e == null || f == null || a == null) {
			return false;
		}
		return a.isConsistent(e.getLength(), f.getLength());
	}
	
	/**
	 * Set the alignment.
	 * 
	 * @param a the new alignment
	 */
	public void setAlignment(Alignment a) {
		this.a = a;
	}
	
	/**
	 * @return the alignment
	 */
	public Alignment getAlignment() {
		return a;
	}

	/**
	 * @return the English sentence
	 */
	public Sentence getSourceSentence() {
		return e;
	}

	/**
	 * @return the French sentence
	 */
	public Sentence getTargetSentence() {
		return f;
	}
	
	/**
	 * Set the score.
	 * 
	 * @param score the new score
	 */
	public void setScore(double score) {
		this.score = score;
	}
	
	/**
	 * @return the alignment score
	 */
	public double getScore() {
		return score;
	}
	
	/**
	 * Default iterator implementation.
	 * 
	 * @see eachTargetPhoneme()
	 */
	@Override
	public Iterator<AlignmentPosition> iterator() {
		return a.eachTargetPhoneme(e, f);
	}
	
	/**
	 * This iterator goes over each position in the French phoneme string. For
	 * each position, corresponding values are encapsulated in 
	 * AlignmentPosition instances.
	 */
	public Iterable<AlignmentPosition> eachTargetPhoneme() {
		return new Iterable<AlignmentPosition>() {
			@Override
			public Iterator<AlignmentPosition> iterator() {
				return a.eachTargetPhoneme(e, f);
			}
		};
	}
	
	/**
	 * Use this iterator for iterating over the set of French words. This is
	 * the same as {@link #eachTargetPhoneme()} reduced to phoneme positions 
	 * with word beginnings. Note that the trgtPhoneme is always -1. We assume
	 * that the first phoneme of each word has no special dependencies.
	 */
	public Iterable<AlignmentPosition> eachTargetWord() {
		return new Iterable<AlignmentPosition>() {
			@Override
			public Iterator<AlignmentPosition> iterator() {
				return a.eachTargetWord(e, f);
			}
		};
	}
	
	/**
	 * This iterator goes through each English word and its fertility.
	 * 
	 * @see #eachSourceWordWithoutNull()
	 */
	public Iterable<AlignmentSourceWord> eachSourceWord() {
		return new Iterable<AlignmentSourceWord>() {
			@Override
			public Iterator<AlignmentSourceWord> iterator() {
				return a.eachSourceWord(e, f);
			}
		};
	}
	
	/**
	 * This iterator goes through each English word and its fertility, leaving
	 * out the NULL word.
	 * 
	 * @see #eachSourceWord()
	 */
	public Iterable<AlignmentSourceWord> eachSourceWordWithoutNull() {
		return new Iterable<AlignmentSourceWord>() {
			@Override
			public Iterator<AlignmentSourceWord> iterator() {
				Iterator<AlignmentSourceWord> it = a.eachSourceWord(e, f);
				it.next();
				return it;
			}
		};
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return a.toString(e, f);
	}

	/**
	 * Clones the alignment, copies the references to source and target
	 * sentence.
	 * 
	 * @return
	 */
	@Override
	public Object clone() {
		return new SentenceAlignment((Alignment) a.clone(), e, f, score);
	}
}
